<?php

namespace App\Trip\Wechat;

class WxBizDataCrypt
{
    const ERRORS
        = [
            0      => 'success',
            -41001 => 'encodingAesKey 非法',
            -41003 => 'aes 解密失败',
            -41004 => '解密后得到的buffer非法',
            -41005 => 'base64加密失败',
            -41016 => 'base64解密失败',
        ];
    public static int $OK                = 0;
    public static int $IllegalAesKey     = -41001;
    public static int $IllegalIv         = -41002;
    public static int $IllegalBuffer     = -41003;
    public static int $DecodeBase64Error = -41004;
    private string    $appid;
    private string    $sessionKey;
    /**
     * 解密后的原文
     * @var string
     */
    private string $decryptData = '';
    private int    $error_code  = 0;
    private string $error_msg   = '';

    /**
     * 构造函数
     * @param $sessionKey string 用户在小程序登录后获取的会话密钥
     * @param $appid string 小程序的appid
     */
    public function __construct(string $appid, string $sessionKey)
    {
        $this->sessionKey = $sessionKey;
        $this->appid      = $appid;
    }


    /**
     * 检验数据的真实性，并且获取解密后的明文.
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @return int 成功0，失败返回对应的错误码
     */
    public function decryptData(string $encryptedData, string $iv): int
    {
        if (strlen($this->sessionKey) != 24) {
            return $this->error_code = self::$IllegalAesKey;
        }
        $aesKey = base64_decode($this->sessionKey);
        if (strlen($iv) != 24) {
            return $this->error_code = self::$IllegalIv;
        }
        $aesIV     = base64_decode($iv);
        $aesCipher = base64_decode($encryptedData);
        $result    = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        $dataObj   = json_decode($result);
        if ($dataObj == null) {
            return $this->error_code = self::$IllegalBuffer;
        }
        if ($dataObj->watermark->appid != $this->appid) {
            return $this->error_code = self::$IllegalBuffer;
        }
        $this->decryptData = $result;
        return $this->error_code = self::$OK;
    }

    public function getDecryptData(): string
    {
        return $this->decryptData;
    }

    public function getErrorCode(): int
    {
        return $this->error_code;
    }

    public function getErrorMsg(): string
    {
        return self::ERRORS[$this->error_code];
    }
}